"""
在项目的工具库中创建一个新的py文件
在这个py文件中  定义自己的请求类 在功能程序(bqg_reptile.py)中可以继承此类 来拥有类中的所有方法  这叫做公共类的抽离  重复代码的抽取
"""
import json
import os
import random

import requests

from xunter_utils.work_utils import work_logger


# 定义一个客户端  可以发送请求 GET和POSt

class ChromeClient:
    # 增加会话属性 保存requests请求对象 接下来的请求都在会话中进行 并且将请求需要的一些反反爬参数设置
    def __init__(self, proxy_dir: str = 'proxy_ips'):
        """
        初始化
        :param proxy_dir:代理IP目录
        """
        self.session = requests.Session()
        self.session.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        }
        # 代理池
        self.proxies = {

        }
        if proxy_dir:
            # 更新代理池
            for file_name in os.listdir(proxy_dir):  # 到指定的文件夹中拿到里面的代理ip池的文件
                with open(f'{proxy_dir}/{file_name}', 'r', encoding='utf-8') as f:  # 读取里面的文件
                    self.proxies.update(json.load(f))  # 更新代理IP池(将文件中的代理ip合并到代理池中)  将json文件数据反序列化变成python数据

    @work_logger()  # 为了记录程序的运行状况 我们还需要有日志
    def send_request(self, *args, **kwargs) -> requests.Response:
        """
        在功能程序中调用自己封装好的send_request请求方法会传入许多不同的参数  所以我们用两个不定长进行接收
        发送请求
        :param url: 请求地址
        :return: 请求的响应对象
        timeout=6 表示响应超过6秒就报超时错误
        """
        kwargs['timeout'] = 10
        res = self.session.get(*args, **kwargs)
        if res.status_code // 100 != 2:
            raise TimeoutError('响应状态码异常{res.status_code}:{res.text}')
        return res

    @work_logger()  # 为了记录程序的运行状况 我们还需要有日志
    def send_request_post(self, *args, **kwargs) -> requests.Response:
        """
        在功能程序中调用自己封装好的send_request请求方法会传入许多不同的参数  所以我们用两个不定长进行接收
        发送请求
        :param url: 请求地址
        :return: 请求的响应对象
        timeout=6 表示响应超过6秒就报超时错误
        """
        res = self.session.post(*args, **kwargs)
        if res.status_code // 100 != 2:
            raise TimeoutError('响应状态码异常{res.status_code}:{res.text}')
        return res

    def get_random_ip(self) -> str:
        """
        在线获取随机ip
        :return:
        """
        res = requests.get('https://proxypool.scrape.center/random', headers=self.session.headers)
        return res.text

    def set_proxy_session(self) -> str:
        """
        给session设置代理
        :return:
        """
        ips = list(self.proxies.keys())  # 得到所有的代理ip和对应的端口
        if ips:
            ip = random.choice(ips)  # 如果有代理ip就从中随机取一个
        else:
            ip = self.get_random_ip()  # 没有就在线拿

        proxies = {
            'http': 'http://' + ip,
            'https': 'http://' + ip
        }

        self.session.proxies = proxies

        return ip

    def send_request_proxy(self, *args, **kwargs):
        """
        使用代理ip发送get请求
        其实就是给session设置个代理IP 不行的话就再设置另一个
        请求方法还是用send_requests方法
        :param args:
        :param kwargs:
        :return:
        """
        while True:
            # 一直从代理池中获取代理ip 并设置
            ip = None
            if not self.session.proxies:
                ip = self.set_proxy_session()
                print(ip, self.proxies.get(ip, ['online'])[0], len(self.proxies))  # 当前的代理ip 来源 代理池剩余数量
                # print(ip, len(self.proxies))

            try:
                res = self.send_request(*args, **kwargs)
                if res:
                    return res
                else:  # 没有正确获取到响应对象
                    if self.proxies and ip:
                        self.proxies.pop(ip)  # 把失败的代理从代理池中移除
                    self.session.proxies = None
            except Exception:
                if self.proxies and ip:
                    self.proxies.pop(ip)  # 把失败的代理从代理池中移除
                self.session.proxies = None
